﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using GoldParser;

namespace QLAB
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listView1.Items.Clear();
            treeView1.Nodes.Clear();
            ParseTreeGenerator generator = new ParseTreeGenerator();
            generator.ParseAction = new ParseActionDelegate(AddParseAction);
            
            if (generator.Parse(textBox1.Text))
            {
                NonTerminalNode parseNode = generator.ParseTree as NonTerminalNode;
                BuildParseTree(parseNode);
            }
        }

        private void expandAllNodesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            treeView1.ExpandAll();
        }

        private void collapseAllNodesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            treeView1.CollapseAll();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ParserFactory.InitializeFactoryFromFile(
                Path.GetDirectoryName(Application.ExecutablePath) + @"\QLAB.cgt");

            contextMenuStrip1.ImageList = imageList1;
            expandAllNodesToolStripMenuItem.ImageIndex = Convert.ToInt32(IconType.Expand);
            collapseAllNodesToolStripMenuItem.ImageIndex = Convert.ToInt32(IconType.Collapse);
        }

        private void AddParseAction(Parser parser, ParseMessage action, string value, string description)
        {
            string actionName = "Error";

            switch (action)
            {
                case ParseMessage.TokenRead:

                    if (parser.TokenLineNumber > 1 || parser.TokenLinePosition > 1)
                    {
                        listView1.Items.Add(new ListViewItem(new string[] { 
                            "Shift", parser.CurrentLRState.Index.ToString(), 
                            "", "", "", "Shifted to state " + parser.CurrentLRState.Index}, 
                            Convert.ToInt32(IconType.Shift), Color.Olive, Color.White, listView1.Font));
                        listView1.Items.Add(new ListViewItem(new string[] { 
                            "Token Read", parser.CurrentLRState.Index.ToString(), parser.TokenLineNumber.ToString(), 
                            parser.TokenLinePosition.ToString(), value, description },
                            Convert.ToInt32(IconType.Token), Color.Black, Color.White, listView1.Font));
                    }
                    else
                    {
                        listView1.Items.Add(new ListViewItem(new string[] { 
                            "Token Read", parser.CurrentLRState.Index.ToString(), parser.TokenLineNumber.ToString(), 
                            parser.TokenLinePosition.ToString(), value, description },
                            Convert.ToInt32(IconType.Token), Color.Black, Color.White, listView1.Font));
                    }

                    break;

                case ParseMessage.Reduction:

                    listView1.Items.Add(new ListViewItem(new string[] { 
                        "Reduce", parser.CurrentLRState.Index.ToString(), "", "", value, description },
                        Convert.ToInt32(IconType.Reduction), Color.DarkRed, Color.White, listView1.Font));

                    break;

                case ParseMessage.Accept:

                    listView1.Items.Add(new ListViewItem(new string[] { 
                        "Accept", parser.CurrentLRState.Index.ToString(), "", "", value, description },
                        Convert.ToInt32(IconType.Accept), Color.DarkGreen, Color.White, listView1.Font));

                    break;

                case ParseMessage.NotLoadedError:
                    actionName = "Load Error";
                    goto default;

                case ParseMessage.LexicalError:
                    actionName = "Lexical Error";
                    goto default;

                case ParseMessage.SyntaxError:
                    actionName = "Syntax Error";
                    goto default;

                case ParseMessage.CommentError:
                    actionName = "Comment Error";
                    goto default;

                case ParseMessage.InternalError:
                    actionName = "Internal Error";
                    goto default;


                default:

                    listView1.Items.Add(new ListViewItem(new string[] { 
                        actionName, parser.CurrentLRState.Index.ToString(), parser.TokenLineNumber.ToString(), 
                        parser.TokenLinePosition.ToString(), value, description },
                        Convert.ToInt32(IconType.Error), Color.Red, Color.White, listView1.Font));

                    break;
            }

        }


        private void BuildParseTree(NonTerminalNode nonTerminal)
        {
            treeView1.Nodes.Clear();
            
            TreeNode node = new TreeNode(nonTerminal.Rule.ToString(), 
                Convert.ToInt32(IconType.Reduction), 
                Convert.ToInt32(IconType.Reduction));
            treeView1.Nodes.Add(node);
            for (int i = 0; i < nonTerminal.Count; i++)
            {
                ParseNode childNode = nonTerminal[i];
                BuildParseTree(childNode, node);
            }
            node.Expand();
        }

        private void BuildParseTree(ParseNode parseNode, TreeNode parentNode)
        {
            NonTerminalNode nonTerminal = parseNode as NonTerminalNode;

            if (nonTerminal != null)
            {
                TreeNode node = new TreeNode(nonTerminal.Rule.ToString(),
                    Convert.ToInt32(IconType.Reduction),
                    Convert.ToInt32(IconType.Reduction));
                parentNode.Nodes.Add(node);
                for (int i = 0; i < nonTerminal.Count; i++)
                {
                    ParseNode childNode = nonTerminal[i];
                    BuildParseTree(childNode, node);
                }
            }
            else
            {
                TreeNode node = new TreeNode(parseNode.ToString(),
                    Convert.ToInt32(IconType.Token),
                    Convert.ToInt32(IconType.Token));
                parentNode.Nodes.Add(node);
            }
        }

        private enum IconType
        {
            Token = 7,
            Reduction = 6,
            Accept = 55,
            Error = 2,
            Shift = 92,
            Expand = 81,
            Collapse = 80
        }

    }
}
